Let’s Build a Chatbot

Using GitHub Copilot, ChatGPT, & more in your favorite IDE

James Wade

Creating OpenAI API Calls

An Example from OpenAI Documentation

curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]
}'

Constructing Messages for OpenAI

The message body:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"}
  ]
}

Send requests with {httr2}

library(httr2)
library(purrr)

Send requests with {httr2}

library(httr2)
library(purrr)

# construct the message body
user_message <- list(list(role = "user", content = "Hello"))
body <- list(model = "gpt-3.5-turbo", messages = user_message)
api_key <- Sys.getenv("OPENAI_API_KEY")

Send requests with {httr2}

library(httr2)
library(purrr)

# construct the message body
user_message <- list(list(role = "user", content = "Hello!"))
body <- list(model = "gpt-3.5-turbo", messages = user_message)
api_key <- Sys.getenv("OPENAI_API_KEY")

# send the request
resp <-
  request("https://api.openai.com/v1") |> 
  req_url_path_append("chat/completions") |> 
  req_auth_bearer_token(token = api_key) |> 
  req_body_json(body) |> 
  req_perform()

Send requests with {httr2}

# construct the message body
user_message <- list(list(role = "user", content = "Hello!"))
body <- list(model = "gpt-3.5-turbo", messages = user_message)
api_key <- Sys.getenv("OPENAI_API_KEY")

# send the request
resp <-
  request("https://api.openai.com/v1") |>
  req_url_path_append("chat/completions") |> 
  req_auth_bearer_token(token = api_key) |> 
  req_body_json(body) |> 
  req_perform()

# process the repsonse
resp |>
  resp_body_json(simplifyVector = TRUE) |> 
  pluck("choices", "message", "content")
[1] "Hello! How can I assist you today?"

Examining the Response

resp |> 
  resp_body_json(simplifyVector = TRUE)
$id
[1] "chatcmpl-8rAt2zMR94EqmcJM0eWx9NHV96gU9"

$object
[1] "chat.completion"

$created
[1] 1707683924

$model
[1] "gpt-3.5-turbo-0613"

$choices
  index message.role                    message.content logprobs finish_reason
1     0    assistant Hello! How can I assist you today?       NA          stop

$usage
$usage$prompt_tokens
[1] 9

$usage$completion_tokens
[1] 9

$usage$total_tokens
[1] 18


$system_fingerprint
NULL

Wrapping it in a function

library(httr2)
library(purrr)

chat <- function(message, api_key = Sys.getenv("OPENAI_API_KEY")) {
  user_message <- list(list(role = "user", content = message))
  body <- list(model = "gpt-3.5-turbo",
               messages = user_message)
  resp <-
    request("https://api.openai.com/v1") |> 
    req_url_path_append("chat/completions") |> 
    req_auth_bearer_token(token = api_key) |> 
    req_body_json(body) |> 
    req_perform()
  
  resp |> 
    resp_body_json(simplifyVector = TRUE) |> 
    pluck("choices", "message", "content")
}

Trying out chat()

chat("What is your favorite color?")
[1] "As an AI, I don't have personal preferences or perceptions, so I don't have a favorite color."

chat("Show me a simple ggplot2 example. Only code with comments. Be brief.")
[1] "# Load required packages\nlibrary(ggplot2)\n\n# Create a data frame\ndata <- data.frame(x = c(1, 2, 3, 4, 5), \n                   y = c(2, 4, 6, 8, 10))\n\n# Create a scatterplot using ggplot2\nggplot(data, aes(x, y)) +\n  geom_point()"

A Prettier Reponse

answer <- chat("Make a ggplot2 in an RMarkdown document and briefly tell me
               what you made.")
answer |> cat()
Sure! Here's an example of a ggplot2 code snippet that you can include in an RMarkdown document:

```{r ggplot_example, echo=FALSE}
library(ggplot2)

# Create a simple scatter plot
data <- data.frame(x = c(1, 2, 3, 4, 5), y = c(2, 4, 6, 8, 10))

ggplot(data, aes(x = x, y = y)) +
  geom_point() +
  labs(title = "Scatter Plot Example",
       x = "X Values",
       y = "Y Values")
```

In this ggplot2 example, we create a scatter plot by mapping the 'x' variable to the x-axis and the 'y' variable to the y-axis. We then add points using `geom_point()` and provide labels for the title, x-axis, and y-axis using the `labs()` function.

You can customize this example by modifying the values in the `data.frame()` or changing the aesthetics, point shapes, colors, etc.

When you compile the RMarkdown document, it will generate the scatter plot and display it in the output document (e.g., HTML, PDF, etc.).

An Even Prettier Response

answer |> shiny::markdown()

Sure! Here's an example of a ggplot2 code snippet that you can include in an RMarkdown document:

library(ggplot2)

# Create a simple scatter plot
data <- data.frame(x = c(1, 2, 3, 4, 5), y = c(2, 4, 6, 8, 10))

ggplot(data, aes(x = x, y = y)) +
  geom_point() +
  labs(title = "Scatter Plot Example",
       x = "X Values",
       y = "Y Values")

In this ggplot2 example, we create a scatter plot by mapping the 'x' variable to the x-axis and the 'y' variable to the y-axis. We then add points using geom_point() and provide labels for the title, x-axis, and y-axis using the labs() function.

You can customize this example by modifying the values in the data.frame() or changing the aesthetics, point shapes, colors, etc.

When you compile the RMarkdown document, it will generate the scatter plot and display it in the output document (e.g., HTML, PDF, etc.).

Some Helper Functions

chat()

chat <- function(user_message, 
                 history = NULL,
                 system_prompt = c("general", "code"),
                 api_key = Sys.getenv("OPENAI_API_KEY")) {
  system   <- get_system_prompt(system_prompt)
  prompt   <- prepare_prompt(user_message, system_prompt, history)
  base_url <- "https://api.openai.com/v1"
  body     <- list(model = "gpt-3.5-turbo",
                   messages = prompt)
  
  # <httr2_request_pipeline>
  # <process_response>
}

Helper Functions

get_system_prompt()

get_system_prompt <- function(system = c("general", "code")) {
  instructions <- 
    switch(system,
           "general" = "You are a helpful assistant.",
           "code"    = "<code_assistant_prompt>")
  list(list(role = "system", content = instructions))
}


prepare_prompt()

prepare_prompt <- function(user_message, system_prompt, history) {
  user_prompt <-  list(list(role = "user", content = user_message))
  c(system_prompt, history, user_prompt) |> compact()
}